﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Security.Permissions;
using System.ComponentModel.Design;
using System.Drawing.Design;
using System.Web.UI.HtmlControls;

namespace jQuery.WebControls.UI
{    
    /// <summary>
    /// Control web contenedor al que se le pueden añadir 1 o varios controles Tab que son ordenados en la página
    /// web en forma de pestañas o en Accordion.
    /// </summary>
    [AspNetHostingPermission(SecurityAction.Demand,
        Level = AspNetHostingPermissionLevel.Minimal),
    AspNetHostingPermission(SecurityAction.InheritanceDemand,
        Level = AspNetHostingPermissionLevel.Minimal)]
    [DefaultProperty("Tabs")]        
    [Designer(typeof(TabControlDesigner))]    
    [ToolboxData("<{0}:TabControl runat=server></{0}:TabControl>")]    
    public class TabControl : Panel, INamingContainer, IPostBackEventHandler
    {
        public event TabIndexChanged TabControlIndexChanged;
        public enum HeightStyles{
            /// <summary>
            /// All panels will be set to the height of the tallest panel
            /// </summary>
            auto,
            /// <summary>
            /// Expand to the available height based on the tabs' parent height
            /// </summary>
            fill,
            /// <summary>
            /// Each panel will be only as tall as its content
            /// </summary>
            content
        }
        List<Tab> tabs;
        private jQueryScriptManager jQueryMngr;
        private bool vAutoHeight;
        private HeightStyles vHeighStyle = HeightStyles.auto;

        #region Miembros de IjQueryWebControl
        private ClientScriptProxy ClientScriptProxy
        {
            get 
            {
                return ClientScriptProxy.Current;
            }
        }
        #endregion

        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);
            if (!Page.IsPostBack)
            {
                if (!DesignMode)
                    CheckQueryManager();
            }
            
        }

        #region PROPIEDADES
        [Category("Appearance")]
        [DefaultValue(AnimationAccordion.None)]
        [Description("")]
        public HeightStyles HeightStyle
        {
            get { return vHeighStyle; }
            set { vHeighStyle = value; }
        }
        /// <summary>
        /// Obtiene o establece el efecto que se le aplicara al control cuando se cambie de un Tab a otro cuando 
        /// la propiedad RenderMode sea Accordion
        /// </summary>
        [Category("Appearance")]
        [DefaultValue(AnimationAccordion.None)]
        [Description("Solo válido para el tipo de tabulacion Accordion")]
        public AnimationAccordion EfectoAnimacionAccordeon
        {
            get
            {
                if (ViewState["eaa"] == null)
                {
                    ViewState.Add("eaa", AnimationAccordion.None);
                }
                return (AnimationAccordion)ViewState["eaa"];
            }
            set
            {
                ViewState["eaa"] = value;
            }
        }
        /// <summary>
        /// Obtiene o establece el efecto que se le aplicara al control cuando se cambie de un Tab a otro cuando 
        /// la propiedad RenderMode sea Tabs
        /// </summary>
        [Category("Appearance")]
        [DefaultValue(AnimationAccordion.None)]
        [Description("Solo válido para el tipo de tabulacion Accordion")]
        public AnimationTabs EfectoAnimationTabs
        {
            get
            {
                if (ViewState["eap"] == null)
                {
                    ViewState.Add("eap", AnimationTabs.None);
                }
                return (AnimationTabs)ViewState["eap"];
            }
            set
            {
                ViewState["eap"] = value;
            }
        }
        /// <summary>
        /// Obtiene o establece la presentación del control en HTML
        /// </summary>
        [Category("Appearance")]
        [DefaultValue(TabRenderMode.Tabs)]
        [Description("")]
        public TabRenderMode RenderMode
        {
            get
            {
                if (ViewState["tb"] == null)
                {
                    ViewState.Add("tb", TabRenderMode.Tabs);
                }
                return (TabRenderMode)ViewState["tb"];
            }
            set
            {
                if (RenderMode != value)
                {
                    ViewState["tb"] = value;                    
                    CreateChildControls();
                }                
            }
        }
        
        /// <summary>
        /// Obtiene o establece la colección de controles Tab. 
        /// </summary>
        [Category("Data")]
        [Description("Listado de pestañas que se van a mostrar")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
        Editor(typeof(CollectionEditor), typeof(UITypeEditor))]
        [PersistenceMode(PersistenceMode.InnerProperty)]                
        public List<Tab> Tabs
        {
            get
            {                
                if (tabs == null)
                {
                    tabs = new List<Tab>();
                    for (int i = 0; i < Controls.Count; i++)
                    {
                        if (Controls[i].GetType() == typeof(Tab))
                        {
                            tabs.Add(Controls[i] as Tab);
                        }
                    }
                }                
                return tabs;                
            }            
        }
        /// <summary>
        /// Obtiene o establece el indice del Tab que debe ser mostrado
        /// </summary>
        [Bindable(true)]
        [Category("Data")]
        [DefaultValue("1")]
        [Localizable(true)]
        public short SelectedIndex
        {
            get
            {
                short aux = 0;
                if (ViewState["sIndex"] == null)
                {
                    ViewState.Add("sIndex", 0);
                }
                else
                {
                    aux = short.Parse(ViewState["sIndex"].ToString());
                }
                if (Page.Request.Form[idSelectedIndexHidden] != null)
                {
                    ViewState["sIndex"] = Page.Request.Form[idSelectedIndexHidden].ToString();
                    aux = short.Parse(ViewState["sIndex"].ToString());
                    for (int i = 0; i < Tabs.Count; i++)
                    {
                        if (!Tabs[i].Visible && i < short.Parse(ViewState["sIndex"].ToString()))
                        {
                            aux--;
                        }
                    }
                }
                
                return aux;
            }
            set
            {                
                ViewState["sIndex"] = value;                
            }
        }
        /// <summary>
        /// Gets or sets if the tabs have the same height getting the greater height for 
        /// the rest of them if its value is true
        /// </summary>
        [Category("Appearance")]
        [DefaultValue(false)]
        [Description("Gets or sets if the tabs have the same height getting the greater height for the rest of them if its value is true")]
        [Obsolete("Use the HeightStyle property")]
        public bool AutoHeight
        {
            get
            {                
                return vAutoHeight;
            }
            set
            {
                if (true) HeightStyle = HeightStyles.auto;
                vAutoHeight = value;
            }
        }
        #endregion

        #region PROPIEDADES PRIVADAS
        /// <summary>
        /// Obtiene el identificador HTML del control de cliente
        /// </summary>
        private string IdTabControlClient { get { return "m" + ClientID; } }
        /// <summary>
        /// Obtiene el identificador del input hidden donde se guarda el indice seleccionad
        /// </summary>
        private string idSelectedIndexHidden { get { return IdTabControlClient + "SelectedIndex"; } }
        #endregion    
                 
        #region SCRIPTS
        /// <summary>
        /// Genera un control HtmlGenericControl de una etiqueta script con el código necesario para generar el Accordion
        /// </summary>
        /// <returns></returns>
        private string ScriptAccordion()
        {
            string txtScript = "$('#" + IdTabControlClient + "').accordion({ heightStyle: '" + HeightStyle.ToString() + "', header: 'h3', active: " + SelectedIndex.ToString() +
                (EfectoAnimacionAccordeon != AnimationAccordion.None ? ", animated: '" + EfectoAnimacionAccordeon.ToString().ToLower() + "'" : "") +
                (TabControlIndexChanged != null ? "," + ScriptPostBackIndexChanged() : "") + "  });";            
            return txtScript;
        }
        /// <summary>
        /// Genera un control HtmlGenericControl de una etiqueta script con el código necesario para generar las Tabs
        /// </summary>
        /// <returns></returns>
        private string ScriptTabs()
        {
            string txtScript = "$('#" + IdTabControlClient + "').tabs({ heightStyle: '" + HeightStyle.ToString() + "', active:" + SelectedIndex.ToString() +
                (EfectoAnimationTabs != AnimationTabs.None ? ", fx: { opacity: '" + EfectoAnimationTabs.ToString().ToLower() + "' }" : "") +
                (TabControlIndexChanged != null ? "," + ScriptPostBackIndexChanged() : "") + " });";
           
            return txtScript;
        }

        private string ScriptPostBackIndexChanged()
        {
            return "activate: function(event, ui){" + 
                "var index = ui.index; " + 
                Page.ClientScript.GetPostBackEventReference(this, "'+index+'") +
                "}";
            
        }
        #endregion

        #region CREATE CHILDS TIPO TABULACION
        /// <summary>
        /// Crea la coleccion de controles necesarios para representar el control en HTML en forma de Accordion
        /// </summary>  
        private void CreateChildsAccordion()
        {            
            this.Controls.Add(new LiteralControl("<div id='" + IdTabControlClient + "' style='" + ControlTabStyle() + "'>"));
            for (int i = 0; i < Tabs.Count; i++)
            {
                this.Controls.Add(new LiteralControl("<div><h3><a href='#' onclick=\"$('#" +
                    idSelectedIndexHidden + "').val(" + i.ToString() + ");\">" + Tabs[i].TabTitle + 
                    "</a></h3><div>"));                                
                this.Controls.Add(Tabs[i]);
                this.Controls.Add(new LiteralControl("</div></div>"));
            }
            this.Controls.Add(new LiteralControl("</div>"));                
        }
        /// <summary>
        /// Crea la coleccion de controles necesarios para representar el control en HTML en forma de Pestañas
        /// </summary>  
        private void CreateChildsTabs()
        {            
            this.Controls.Add(new LiteralControl("<div id='" + IdTabControlClient + "' style='" + ControlTabStyle() + "'> <ul>"));
            for (int i = 0; i < Tabs.Count; i++)
            {
                this.Controls.Add(new LiteralControl("<li><a href='#" + IdTabControlClient + "-tab-" + i.ToString() + "' onclick=\"$('#" +
                    idSelectedIndexHidden + "').val(" + i.ToString() + ");\" title='" + Tabs[i].TabTitle + "'>" + Tabs[i].TabTitle + "</a></li>"));
            }
            this.Controls.Add(new LiteralControl("</ul>"));

            for (int i = 0; i < Tabs.Count; i++)
            {
                this.Controls.Add(new LiteralControl("<div id='" + IdTabControlClient + "-tab-" + i.ToString() + "' style='" + TabStyle(Tabs[i]) + "'>"));
                this.Controls.Add(Tabs[i]);                
                this.Controls.Add(new LiteralControl("</div>"));
            }
            this.Controls.Add(new LiteralControl("</div>"));                         
        }               

        #endregion

        /// <summary>
        /// Genera la salida HTML del control
        /// </summary>
        /// <param name="writer"></param>
        protected override void Render(HtmlTextWriter writer)
        {            
            writer.Write("<input type='hidden' id='" + idSelectedIndexHidden +
            "' name='" + idSelectedIndexHidden + "' value='" + SelectedIndex.ToString() + "' />");

            switch (RenderMode)
            {
                case TabRenderMode.Tabs:
                    ClientScriptProxy.RegisterStartupScript(Page, GetType(),
                        String.Format("tabControl_{0}", IdTabControlClient), ScriptTabs(), true);
                    RenderTabs(writer);
                    break;
                case TabRenderMode.Accordion:
                    ClientScriptProxy.RegisterStartupScript(Page, GetType(),
                        String.Format("tabControl_{0}", IdTabControlClient), ScriptAccordion(), true);
                    RenderAccordion(writer);
                    break;
            }
        }

        #region RENDER CONTROL TIPO TABULACION        

        private void RenderTabs(HtmlTextWriter writer)
        {
            writer.Write("<div id='" + IdTabControlClient + "' style='" + ControlTabStyle() + "'> <ul>");
            for (int i = 0; i < Tabs.Count; i++)
            {
                if (Tabs[i].Visible)
                {
                    writer.Write("<li><a href='#" + IdTabControlClient + "-tab-" + i.ToString() + "' onclick=\"$('#" +
                        idSelectedIndexHidden + "').val(" + i.ToString() + ");\" title='" + Tabs[i].TabTitle + "'>" + Tabs[i].TabTitle + "</a></li>");
                }
            }
            writer.Write("</ul>");

            for (int i = 0; i < Tabs.Count; i++)
            {
                if (Tabs[i].Visible)
                {
                    writer.Write("<div id='" + IdTabControlClient + "-tab-" + i.ToString() + "' style='" + TabStyle(Tabs[i]) + "'>");
                    Tabs[i].RenderControl(writer);
                    writer.Write("</div>");
                }
            }
            writer.Write("</div>");            
        }

        private void RenderAccordion(HtmlTextWriter writer)
        {
            writer.Write("<div id='" + IdTabControlClient + "' style='" + ControlTabStyle() + "'>");
            for (int i = 0; i < Tabs.Count; i++)
            {
                if (Tabs[i].Visible)
                {
                    writer.Write("<div><h3><a href='#' onclick=\"$('#" +
                        idSelectedIndexHidden + "').val(" + i.ToString() + ");\">" + Tabs[i].TabTitle +
                        "</a></h3><div>");
                    Tabs[i].RenderControl(writer);
                    writer.Write("</div></div>");
                }
            }
            writer.Write("</div>");            
        }
        #endregion

        /// <summary>
        /// Devuelve una cadena de texto con el ancho y alto en HTML que debe tener el ControlTab
        /// </summary>
        /// <returns></returns>
        private string ControlTabStyle()
        {
            string style = "";
            if (!Height.IsEmpty || !Width.IsEmpty)
                style += "overflow: auto;";
            if (!Height.IsEmpty)
                style += String.Format("height: {0};", Height.ToString());
            if (!Width.IsEmpty)
                style += String.Format("width: {0};", Width.ToString());
            if (!Font.Size.IsEmpty)
                style += String.Format("font-size: {0};", Font.Size.ToString());
            if (Font.Bold.Equals(true))
                style += String.Format("font-weight: bold;");
            if (Font.Italic.Equals(true))
                style += String.Format("font-style: italic;");
            if (!ForeColor.IsEmpty)
                style += String.Format("color: {0};", System.Drawing.ColorTranslator.ToHtml(ForeColor));
            return style;
        }
        /// <summary>
        /// Devuelve una cadena de texto con el ancho y alto en HTML que debe tener cada Tab que a su vez 
        /// hereda del ancho y alto de su contenedor
        /// </summary>
        /// <returns></returns>
        private string TabStyle(Tab tab)
        {
            string style = "";
            if (!tab.Height.IsEmpty)
                style += String.Format("height: {0}{1};", (Height.Value - 10), Height.Type.ToString());
            if (!Width.IsEmpty)
                style += String.Format("width: {0}{1};", (Width.Value - 10), Width.Type.ToString());
            if (!tab.Font.Size.IsEmpty)
                style += String.Format("font-size: {0};", Font.Size.ToString());
            if (Font.Bold.Equals(true))
                style += String.Format("font-weight: bold;");
            if (tab.Font.Italic.Equals(true))
                style += String.Format("font-style: italic;");
            if (!tab.ForeColor.IsEmpty)
                style += String.Format("color: {0};", System.Drawing.ColorTranslator.ToHtml(ForeColor));
            return style;
        }

        private jQueryScriptManager jQueryManager
        {
            get
            {
                if (jQueryMngr == null)
                    jQueryMngr = Common.Instance.Get_jQueryScriptManager(Page);
                return jQueryMngr;
            }
        }

        private void CheckQueryManager()
        {
            Common.Instance.CheckJQueryScriptManager(Page);
        }

        
        #region Miembros de IPostBackEventHandler
                
        public void RaisePostBackEvent(string eventArgument)
        {            
            if (TabControlIndexChanged != null)
            {
                TabControlIndexChanged(Tabs[SelectedIndex]);
            }
        }
              
        #endregion
    }
}
